#ifndef _STHREAD_H_
#define _STHREAD_H_
/* 
Note: this library requires you to link with the posix threads
library (-lpthread) and the real time library (-lrt) {for
nanosleep}.

   c++ -D_POSIX_PTHREAD_SEMANTICS main.cc sthread.cc -lpthread -lrt
   or 
   g++ -Wall -D_POSIX_PTHREAD_SEMANTICS main.cc sthread.cc -lpthread -lrt
*/

#include <pthread.h>
#include <unistd.h>

/*
 * The normal random() library may not be thread safe
 * so we add a wrapper with locks.
 */
long sutil_random(void);
void sutil_srandom(unsigned seed);

/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*
 * Mutexes.
 */
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/* // Create a mutex with 
 *      smutex_t *mutex = (smutex_t *)malloc(sizeof(smutex_t));
 *      smutex_init(mutex);
 * // Reclaim one
 *      smutex_destroy(mutex);
 *      free(mutex);
 * // Lock and unlock 
 *      smutex_lock(mutex);
 *      smutex_unlock(mutex);
 */
typedef pthread_mutex_t smutex_t;
void smutex_init(smutex_t *mutex);
void smutex_destroy(smutex_t *mutex);
void smutex_lock(smutex_t *mutex);
void smutex_unlock(smutex_t *mutex);


/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*
 * Condition variables.
 */
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
typedef struct scond{
  pthread_cond_t cond;
  smutex_t *mutex;
} scond_t;

void scond_init(scond_t *cond, smutex_t *mutex);
void scond_destroy(scond_t *cond);

/*
 * Condition variables are always associated with state
 * variables that you access before signalling, broadcasting,
 * or waiting. To access the state variable, you must hold
 * the associated mutex. To help enforce this, you 
 * are required to hold the mutex and pass it in as an
 * argument to these functions.
 */
void scond_signal(scond_t *cond, smutex_t *mutex);
void scond_broadcast(scond_t *cond, smutex_t *mutex);
void scond_wait(scond_t *cond, smutex_t *mutex);



/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/*
 * Threads.
 */
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
typedef pthread_t sthread_t;

void sthread_create(sthread_t *thrd,
		    void *(*start_routine)(void*), 
		    void *argToStartRoutine);
void sthread_exit(void);


/*
 * (ALMOST) NEVER USE SLEEP!!!!
 * Sleep is included in this library for the
 * rare instances where you need to sleep for
 * a fixed amount of time and then do something.
 * 
 * One of the most common errors in undergraduate
 * threads projects is using sleep when what
 * should be used is scond_wait().
 *
 * If you use sleep when you should use wait, we 
 * will count off enormous numbers of points
 * on your project!!! If you don't know
 * when to use which, find out before you
 * start writing code!!!
 */
void sthread_sleep(unsigned int seconds, unsigned int nanoseconds);

/* 
 * Give up the processor to another ready thread. Thread
 * remains in "ready" state and can be rescheduled at 
 * scheduler's convenience.
 */
void sthread_yield(void);


#endif 

